package com.hue.gulimail.gulimailware.service.impl;

import com.hue.common.to.mq.WareOrderTaskDetailTo;
import com.hue.gulimail.gulimailware.entity.WareOrderTaskDetailEntity;
import com.hue.gulimail.gulimailware.entity.WareOrderTaskEntity;
import com.hue.gulimail.gulimailware.exception.NotStockException;
import com.hue.gulimail.gulimailware.service.WareOrderTaskDetailService;
import com.hue.gulimail.gulimailware.service.WareOrderTaskService;
import com.hue.gulimail.gulimailware.vo.OrderItemVo;
import com.hue.gulimail.gulimailware.vo.WareLockRes;
import com.hue.gulimail.gulimailware.vo.WareSkuLockVo;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hue.common.utils.PageUtils;
import com.hue.common.utils.Query;

import com.hue.gulimail.gulimailware.dao.WareSkuDao;
import com.hue.gulimail.gulimailware.entity.WareSkuEntity;
import com.hue.gulimail.gulimailware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {
    @Autowired
    private WareOrderTaskService wareOrderTaskService;
    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryWareSkuPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        String skuId = (String) params.get("skuId");
        if (!StringUtils.isEmpty(skuId)) {
            wrapper.eq("sku_id", skuId);
        }
        String wareId = (String) params.get("wareId");
        if (!StringUtils.isEmpty(wareId)) {
            wrapper.eq("ware_id", wareId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

    @Override
    public Map<Long, Boolean> hasStock(List<Long> skuIds) {
        Map<Long, Boolean> hasStock = new HashMap<>();
        for (Long skuId : skuIds) {
            Integer stock = baseMapper.hasStock(skuId);
            hasStock.put(skuId, stock == null ? false : stock > 0);
        }
        return hasStock;
    }

    /**
     * 锁定商品库存
     *
     * @param wareSkuLockVo
     * @return
     */
    @Override
    //默认只要是运行时异常都会回滚
    @Transactional
    public List<WareLockRes> lockOrder(WareSkuLockVo wareSkuLockVo) {
        List<WareLockRes> wareLockResList = new ArrayList<>();

        //创建库存工作单信息
        WareOrderTaskEntity wareOrderTask = new WareOrderTaskEntity();
        wareOrderTask.setOrderSn(wareSkuLockVo.getOrderSn());
        wareOrderTaskService.save(wareOrderTask);

        //需要锁定的商品信息
        List<OrderItemVo> locks = wareSkuLockVo.getLocks();

        //得到skuId和仓库信息
        List<SkuHasStockVo> skuHasStockVos = locks.stream().map(lock -> {
            SkuHasStockVo skuHasStockVo = new SkuHasStockVo();
            skuHasStockVo.setSkuId(lock.getSkuId());
            skuHasStockVo.setCount(lock.getCount());
            skuHasStockVo.setWareIds(baseMapper.wareIdHasSkuIdStock(lock.getSkuId()));
            return skuHasStockVo;
        }).collect(Collectors.toList());

        List<WareOrderTaskDetailTo> wareOrderTaskDetailToList = new ArrayList<>();

        //锁定库存
        for (SkuHasStockVo skuHasStockVo : skuHasStockVos) {
            WareLockRes wareLockRes = new WareLockRes();

            List<Long> wareIds = skuHasStockVo.getWareIds();
            //一个商品没有库存抛出异常，订单创建失败
            if (wareIds == null || wareIds.size() == 0) {
                throw new NotStockException(skuHasStockVo.skuId);
            }
            //有库存就挨个仓库锁定库存，锁定成功或者没有仓库为止
            for (Long wareId : wareIds) {
                Long res = baseMapper.lockSkuId(wareId, skuHasStockVo.getSkuId(), skuHasStockVo.getCount());
                if (res == 0) {
                    //锁定失败
                    throw new NotStockException(skuHasStockVo.skuId);
                }

                //锁定成功，创建一个库存工作任务单详情
                WareOrderTaskDetailEntity wareOrderTaskDetail =
                        new WareOrderTaskDetailEntity(null, skuHasStockVo.getSkuId(),
                                "", skuHasStockVo.getCount(), wareOrderTask.getId(), wareId, 1);
                wareOrderTaskDetailService.save(wareOrderTaskDetail);

                WareOrderTaskDetailTo wareOrderTaskDetailTo = new WareOrderTaskDetailTo();
                BeanUtils.copyProperties(wareOrderTaskDetail, wareOrderTaskDetailTo);
                wareOrderTaskDetailToList.add(wareOrderTaskDetailTo);

                //开始下一个skuId的锁定
                wareLockRes.setRes(true);
                break;
            }

            //所有仓库库存都不足
            if (wareLockRes.getRes() == null || !wareLockRes.getRes()) {
                throw new NotStockException(skuHasStockVo.skuId);
            }
            wareLockResList.add(wareLockRes);
        }

        //库存锁定成功后通知MQ库存锁定成功
        rabbitTemplate.convertAndSend("stock-event-exchange", "stock.locked", wareOrderTaskDetailToList);

        return wareLockResList;
    }

    @Override
    @Transactional
    public void unlockStock(List<WareOrderTaskDetailTo> wareOrderTaskDetailToList) {
        for (WareOrderTaskDetailTo wareOrderTaskDetailTo : wareOrderTaskDetailToList) {
            //解锁库存
            baseMapper.unlockStock(wareOrderTaskDetailTo);
        }

        //修改库存工作单状态为已解锁
        wareOrderTaskDetailService.updateStatus(wareOrderTaskDetailToList.get(0).getTaskId());
    }

    /**
     * 包含了skuId和那些仓库有这个skuId
     */
    @Data
    private static class SkuHasStockVo {
        /**
         * 商品skuId
         */
        private Long skuId;

        /**
         * 需要锁定的数量
         */
        private Integer count;

        /**
         * 仓库id
         */
        private List<Long> wareIds;
    }
}
